//#include "stdfix.h"
#include "ipDataCloud_v6.h"
#include "string.h"
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <sstream>
#include <bitset>
#include <array>
#include <iomanip>
#include <cstdint>
#include "uint128_t.h"


geo_ipv6 *ipv6_instance(const char *file_path) {
    static geo_ipv6 *ipv6_instance = NULL;
    if (ipv6_instance == NULL) {
        ipv6_instance = new geo_ipv6;
        if (ipv6_loadDat(ipv6_instance, file_path) >= 0) {
            return ipv6_instance;
        }

        if (ipv6_instance == NULL) {
            delete(ipv6_instance);
        }
        return NULL;
    }
    return ipv6_instance;
}

int deleteChar(char *s, char c) {
    if (NULL == s) {
        return -1;
    } else {
        char *f = s;
        int i = 0, j = 0;
        while (*s) {
            i++;
            if (*s != c) {
                j++;
                *f = *s;
                f++;
            }
            s++;
        }
        *f = '\0';
        if (i == j)
            return 0;
        return i - j;
    }
}

char *get_addr(geo_ipv6 *p, uint32_t cur) {
    uint32_t offset, length;
    uint32_t j = p->numbers * 12 + 4 + 4 + (cur * 55);
    offset = ipv6_read_int32(p, j + 50);
    length = (uint32_t) p->data[4 + j + 50];
    char *result = (char *) malloc((length + 1) * sizeof(char));
    memcpy(result, p->data + offset, length);
    result[length] = '\0';
    return result;
}


int32_t ipv6_loadDat(geo_ipv6 *p, const char *file_path) {
    FILE *file;
    uint32_t len = 0;
    uint32_t k;
    int i, j;
    uint32_t offset, length;
    file = fopen(file_path, "rb");
    if (file == NULL) {
        printf("%s", "There is no such file or directory");
        return -2;
    }
    fseek(file, 0, SEEK_END);
    len = ftell(file);
    fseek(file, 0, SEEK_SET);
    p->data = (uint8_t *) malloc(len * sizeof(uint8_t));
    fread(p->data, 1, len, file);
    fclose(file);

    p->numbers = ipv6_read_int32(p, 4);
    memset(p->prefStart, 0, sizeof(p->prefStart));
    memset(p->prefEnd, 0, sizeof(p->prefEnd));

    for (k = 0; k < p->numbers; k++) {
        i = k * 12 + 4 + 4;
        p->prefStart[ipv6_read_int32(p, i + 8)] = ipv6_read_int32(p, i);
        p->prefEnd[ipv6_read_int32(p, i + 8)] = ipv6_read_int32(p, i + 4);
    }

    return 0;
}

std::array<std::string, 8> split(const char *str, char delimiter) {
    std::array<std::string, 8> parts;
    size_t i = 0;
    std::stringstream ss(str);
    std::string token;

    while (std::getline(ss, token, delimiter)) {
        if (i < parts.size()) {
            parts[i++] = token;
        }
    }
    return parts;
}

long getPref(const char *ip) {
    // 使用const char*来避免修改传入的ip参数
    std::string str_ip(ip);
    // 找到第一个冒号的位置
    size_t index = str_ip.find(':');
    // 如果没有找到冒号，说明没有前缀部分，返回0
    if (index == std::string::npos) {
        return strtoll(ip, nullptr, 16); // 如果没有冒号，整个IP即为前缀
    }
    // 截取前缀部分
    std::string prefix = str_ip.substr(0, index);
    // 将前缀部分转换为long类型
    long pref = strtoll(prefix.c_str(), nullptr, 16);

    return pref;
}

uint128_t ipv6ToInt(const char *ip) {
    std::string expandedIp = ip;

    // 查找“::”的位置
    size_t pos = expandedIp.find("::");
    if (pos != std::string::npos) {
        // 处理“::”并分割地址
        std::string firstPart = expandedIp.substr(0, pos);
        std::string secondPart = expandedIp.substr(pos + 2); // +2跳过“::”

        // 分割每部分的块
        std::vector<std::string> firstBlocks;
        std::vector<std::string> secondBlocks;

        std::istringstream firstStream(firstPart);
        std::istringstream secondStream(secondPart);
        std::string block;

        while (std::getline(firstStream, block, ':')) {
            if (!block.empty()) {
                firstBlocks.push_back(block);
            }
        }
        while (std::getline(secondStream, block, ':')) {
            if (!block.empty()) {
                secondBlocks.push_back(block);
            }
        }

        // 计算需要填充的零块数
        int totalBlocks = 8;
        int existingBlocks = firstBlocks.size() + secondBlocks.size();
        int missingBlocks = totalBlocks - existingBlocks;

        // 重新组合地址
        std::ostringstream resultStream;
        for (size_t i = 0; i < firstBlocks.size(); ++i) {
            resultStream << firstBlocks[i];
            if (i < firstBlocks.size() - 1 || missingBlocks > 0 || !secondBlocks.empty()) {
                resultStream << ":";
            }
        }
        for (int i = 0; i < missingBlocks; ++i) {
            if (i > 0 || !secondBlocks.empty()) {
                resultStream << ":";
            }
            resultStream << "0000";
        }
        for (size_t i = 0; i < secondBlocks.size(); ++i) {
            if (i > 0 || missingBlocks > 0) {
                resultStream << ":";
            }
            resultStream << secondBlocks[i];
        }

        expandedIp = resultStream.str();
    }

    // 处理地址的每个块，确保每个块都为 4 位
    std::istringstream stream(expandedIp);
    std::string block;
    std::ostringstream finalStream;
    while (std::getline(stream, block, ':')) {
        if (block.length() < 4) {
            block.insert(0, 4 - block.length(), '0');
        }
        finalStream << block;
        if (stream.peek() != EOF) {
            finalStream << ":";
        }
    }
    // 分割每个组
    std::vector<uint16_t> groups;
    std::stringstream ss(expandedIp);
    std::string segment;

    while (std::getline(ss, segment, ':')) {
        if (segment.empty()) continue;
        if (segment.length() > 4) {
            std::cout<< expandedIp << std::endl;
            throw std::invalid_argument("Invalid IPv6 address segment");
        }
        uint16_t value = std::stoi(segment, nullptr, 16);
        groups.push_back(value);
    }

    if (groups.size() != 8) {
        std::cout<< expandedIp << std::endl;
        throw std::invalid_argument("Invalid IPv6 address");
    }

    // 将每个16位数转换为64位整数，并将其分配到128位整数中
    uint64_t upper = 0;
    uint64_t lower = 0;

    for (size_t i = 0; i < 8; ++i) {
        uint64_t value = groups[i];
        if (i < 4) {
            upper = (upper << 16) | value;
        } else {
            lower = (lower << 16) | value;
        }
    }

    return uint128_t(upper, lower);
}

char *ipv6_query(geo_ipv6 *p, const char *ip) {
    uint32_t pref, cur, low, high;
    uint128_t intIP;
    if (NULL == p) {
        return NULL;
    }

    pref = getPref(ip);
    intIP = ipv6ToInt(ip);
    low = p->prefStart[pref];
    high = p->prefEnd[pref];
    if (low == 0 && high == 0) {
        const char *text = "||保留|保留|||||||||||||||";
        char *str = (char *) malloc(strlen(text) + 1); // 分配内存
        if (str) {
            strcpy(str, text); // 将字符串复制到分配的内存中
        }
        return str; // 返回分配的内存
    }
    cur = (low == high) ? low : ipv6_binary_search(p, low, high, intIP);
    return get_addr(p, cur);
}

long ipv6_binary_search(geo_ipv6 *p, long low, long high, uint128_t k) {
    long M = 0;
    char *resultEnd = (char *) malloc((50) * sizeof(char));

    while (low <= high) {
        long mid = (low + high) / 2;
        int j = p->numbers * 12 + 4 + 4 + (mid * 55);
        memset(resultEnd, '\0', 50 * sizeof(char));
        memcpy(resultEnd, p->data + j, 50);
        resultEnd[49] = '\0';
        deleteChar(resultEnd,'*');
        uint128_t endipNum = uint128_t(resultEnd, 10);
        if (endipNum >= k) {
            M = mid;
            if (mid == 0) {
                break;
            }
            high = mid - 1;
        } else
            low = mid + 1;
    }
    free(resultEnd);
    resultEnd = NULL;
    return M;
}


uint32_t ipv6_read_int32(geo_ipv6 *p, int pos) {
    uint32_t result;
    result = (uint32_t) ((p->data[pos]) | (p->data[pos + 1] << 8) | (p->data[pos + 2] << 16) | (p->data[pos + 3] << 24));
    return result;
}
